namespace Plugins.Engine
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using Plugins.Interfaces;
    using Plugins.Library;

    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct PluginTypeInstance : IEquatable<PluginTypeInstance>
    {
        private IPluginService _obj;
        private Type _type;
        private string _service;

        private static Dictionary<IPluginService, IList<Type>> _types = new Dictionary<IPluginService, IList<Type>>();

        public static PluginTypeInstance Get(Type type, IPluginService obj)
        {
            return new PluginTypeInstance(type, obj, PluginTypeHelper.GetTypeName(type));
        }

        public static PluginTypeInstance Register(Type type, IPluginService obj)
        {
            if (!_types.ContainsKey(obj))
            {
                _types.Add(obj, new List<Type>());
            }
            if (!_types[obj].Contains(type))
            {
                _types[obj].Add(type);
            }
            return Get(type, obj);
        }

        public static PluginTypeInstance Unregister(Type type, IPluginService obj)
        {
            if (_types.ContainsKey(obj))
            {
                _types[obj].Remove(type);
                if (_types[obj].Count == 0)
                {
                    _types.Remove(obj);
                }
            }
            return Get(type, obj);
        }

        public static TreeNode[] GetServices()
        {
            TreeNode root = new TreeNode();
            foreach (KeyValuePair<IPluginService, IList<Type>> key in _types)
            {
                string serviceName = PluginTypeHelper.GetTypeName(key.Key.GetType());
                TreeNode[] nodes = root.Nodes.Find(serviceName, false);
                if (nodes != null && nodes.Length > 0)
                {
                    foreach (TreeNode node in nodes)
                    {
                        foreach (Type type in key.Value)
                        {
                            string typeName = PluginTypeHelper.GetTypeName(type);
                            node.Nodes.Add(new TreeNode(typeName));
                        }
                    }
                }
                else
                {
                    TreeNode node = root.Nodes.Add(serviceName, serviceName);
                    foreach (Type type in key.Value)
                    {
                        string typeName = PluginTypeHelper.GetTypeName(type);
                        node.Nodes.Add(new TreeNode(typeName));
                    }
                }
            }
            TreeNode[] result = new TreeNode[root.Nodes.Count];
            root.Nodes.CopyTo(result, 0);
            return result;
        }

        public static TreeNode[] GetContracts()
        {
            TreeNode root = new TreeNode();
            foreach (KeyValuePair<IPluginService, IList<Type>> key in _types)
            {
                string serviceName = PluginTypeHelper.GetTypeName(key.Key.GetType());
                foreach (Type type in key.Value)
                {
                    string typeName = PluginTypeHelper.GetTypeName(type);
                    TreeNode[] nodes = root.Nodes.Find(typeName, false);
                    if (nodes != null && nodes.Length > 0)
                    {
                        foreach (TreeNode node in nodes)
                        {
                            node.Nodes.Add(new TreeNode(serviceName));
                        }
                    }
                    else
                    {
                        TreeNode node = root.Nodes.Add(typeName, typeName);
                        node.Nodes.Add(new TreeNode(serviceName));
                    }
                }
            }
            TreeNode[] result = new TreeNode[root.Nodes.Count];
            root.Nodes.CopyTo(result, 0);
            return result;
        }

        private PluginTypeInstance(Type type, IPluginService obj, string service)
        {
            this._service = service;
            this._type = type;
            this._obj = obj;
        }

        public Guid ContractId
        {
            get
            {
                return this._type.GUID;
            }
        }
        public Guid ServiceId
        {
            get
            {
                return this._obj.Id;
            }
        }
        public bool Equals(PluginTypeInstance other)
        {
            return
                this._obj != null
                && other._obj != null
                && this._type != null
                && other._type != null
                && this._obj.Id == other._obj.Id
                && this._type == other._type;
        }

        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture, "{0}", this._service);
        }

        public override bool Equals(object obj)
        {
            if (obj is PluginTypeInstance)
            {
                return this.Equals((PluginTypeInstance)obj);
            }
            return base.Equals(obj);
        }

        public static bool operator ==(PluginTypeInstance type1, PluginTypeInstance type2)
        {
            return type1._obj != null && type2._obj != null && type1._obj.Id == type2._obj.Id && type1._type == type2._type;
        }

        public static bool operator !=(PluginTypeInstance type1, PluginTypeInstance type2)
        {
            return !(type1 == type2);
        }

        public override int GetHashCode()
        {
            if (this._obj != null)
            {
                if (this._obj.Id != null)
                {
                    return this._obj.Id.GetHashCode();
                }
            }
            return base.GetHashCode();
        }
    }
}

